/**
 * 
 */
package mas;
import java.util.ArrayList;
import java.util.Iterator;

import rinde.sim.core.TimeLapse;
import rinde.sim.core.graph.Point;
import rinde.sim.core.model.communication.CommunicationAPI;
import rinde.sim.core.model.communication.Message;
import rinde.sim.core.model.pdp.PDPModel;
import rinde.sim.core.model.road.RoadModel;

/**
 * @author IVAN
 * @description An instance of this class can be assigned to only one master
 * However it can change of Master when needed
 */
public class Slave extends Truck{
	protected Master currentMaster;
	//todo: remove unused constructors
	/**
	 * @description Constructor
	 */

	public Slave(int radius, double reliability, int agentNumber, RoadModel rm, PDPModel pm, Master currentMaster) {
		super(radius, reliability, rm, pm);
		this.agentNumber = agentNumber;
		this.currentMaster = currentMaster;
	}

	@Override
	public boolean setBox(Box box) {
		boolean assigned = super.setBox(box);
		if (box.getDeliveryZoneNumber() != this.currentMaster.getZoneNumber()){
			this.changeMaster(box);
		}
		return assigned;
	}

	public Master getCurrentMaster() {
		return currentMaster;
	}
	public void setCurrentMaster(Master currentMaster) {
		this.currentMaster = currentMaster;
	}

	@Override
	protected void tickImpl(TimeLapse time) {
		super.tickImpl(time);
	}

	/**
	 * To change of master based on new zone delivery
	 * @param newMaster
	 */
	public void changeMaster(Box box){
		Iterator<Master> it_masters = App.masters.iterator();
		int toRemove = -1;
		Point p = box.getDestination();
		//remove slave from current master's team
		while (it_masters.hasNext()){
			//remove from current Master
			Master currentMaster = it_masters.next();
			if (currentMaster.agentNumber == this.getCurrentMaster().agentNumber){
				Iterator<Slave> it_slaves = currentMaster.getSlaves().iterator();
				int i = 0;
				while(it_slaves.hasNext()){
					if (it_slaves.next().agentNumber == this.agentNumber){
						toRemove = i; 
					}		
					i++;
				}
				if (toRemove > -1)
					currentMaster.getSlaves().remove(toRemove);
			}

			if (currentMaster.getZone().containsPoint(p)){
				this.setCurrentMaster(currentMaster);
				currentMaster.getSlaves().add(this);
			}
		}
	}

	public void doAction(BoxMessage message){
		if(!(this.messagesSpread.containsKey(message.getSender()))){
			messagesSpread.put((Truck) message.getSender(), new ArrayList<Integer>());
		}
		ArrayList<Integer> spreadMessagesOfSender = this.messagesSpread.get(message.getSender());
		int counterOfMessage= message.getCounter();
		if(!(spreadMessagesOfSender.contains(counterOfMessage))){
			spreadMessagesOfSender.add(counterOfMessage);
			if(message.getReceiver()==this){
				if(this.getCurrentMaster()!=message.getSender()){
					this.changeMaster((Master) message.getSender());
				}
				Box box = message.getBox();
				this.setBox(box);
				AcknowledgementMessage ack = new AcknowledgementMessage(this, this.getAndRaiseCounter(), message);
				this.getCurrentMaster().removeUnacknowledgedMessage(message);
				cm.broadcast(ack);
			}
			else{
				cm.broadcast(message);
			}
		}
	}

	/**
	 * To change of master
	 * @param newMaster
	 */
	public void changeMaster(Master newMaster){
		int toRemove = -1;

		Master currentMaster = this.getCurrentMaster();
		Iterator<Slave> it_slaves = currentMaster.getSlaves().iterator();
		int i = 0;
		while(it_slaves.hasNext()){
			if (it_slaves.next().agentNumber == this.agentNumber){
				toRemove = i; 
			}		
			i++;
		}
		if(toRemove>-1){
			currentMaster.getSlaves().remove(toRemove);
			newMaster.getSlaves().add(this);
		}
	}

	@Override
	public void initRoadPDP(RoadModel pRoadModel, PDPModel pPdpModel) {
		// TODO Auto-generated method stub

	}

	@Override
	protected void markToRemove(Box box){
		this.currentMaster.markedToRemove.add(box);
	}

	@Override
	protected void reQueueBox(Box box) {
		this.currentMaster.reQueueBox(box);		
	}
}
